<?php
//获取商品类型全部数据
function _getGoodsTypeListFull(){
	$TablePublicGoodsType = new TablePublicGoodsType();
	return $TablePublicGoodsType->_getGoodsTypeListFull();
}



/*
	### 获取已开通城市数据
	示例：
		$tmp_arr['data'] = getOpenCityInfo();
		exit(json_encode($tmp_arr));
*/
function getOpenCityInfo(){
	$pdo = MyPdoPublic::init();
	$sql = 'select id,code,name,parent_id,level,db_host,db_name from public_city where level < 2 or level = 2 and length(db_host) > 0 and length(db_name) > 0';
	$res = $pdo->dql($sql,array());
	if($res){
		$CityInfo = $res;
		$Province_Arr = $City_Arr = $County_Arr = [];	//用来装载省市县分类后的城市数据
		$Province_Arr2 = $City_Arr2 = $County_Arr2 = [];//用来装载筛选后的城市数据

		// ### 归集省市县数据，同时提取被选取县所属的市id列表
		$City_ids = [];	//临时存放市id
		for($i=0;$i<count($CityInfo);$i++){
			//过滤掉港奥台
			if($CityInfo[$i]['level'] == 0){
				if($CityInfo[$i]['code'] == 710000 || $CityInfo[$i]['code'] == 810000 || $CityInfo[$i]['code'] == 820000){
					continue;
				}
			}
			if($CityInfo[$i]['level'] == 0){			//归集省数据
				$Province_Arr2[] = $CityInfo[$i];
			}
			if($CityInfo[$i]['level'] == 1){			//归集市数据
				$City_Arr2[] = $CityInfo[$i];
			}
			if($CityInfo[$i]['level'] == 2){			//归集县数据
				$County_Arr[] = $CityInfo[$i];
				if(!in_array($CityInfo[$i]['parent_id'],$City_ids)){
					$City_ids[] = intVal($CityInfo[$i]['parent_id']);
				}
			}
		}

		// ### 筛选市数据
		$province_ids = [];//临时存放省id
		for($i=0;$i<count($City_Arr2);$i++){
			for($j=0;$j<count($City_ids);$j++){
				if(intVal($City_ids[$j]) == intVal($City_Arr2[$i]['id'])){
					$City_Arr[] = $City_Arr2[$i];
					if(!in_array($City_Arr2[$i]['parent_id'],$province_ids)){
						$province_ids[] = intVal($City_Arr2[$i]['parent_id']);
					}
				}
			}
		}


		//筛选省数据
		for($i=0;$i<count($Province_Arr2);$i++){
			for($j=0;$j<count($province_ids);$j++){
				if(intVal($province_ids[$j]) == intVal($Province_Arr2[$i]['id'])){
					$Province_Arr[] = $Province_Arr2[$i];
				}
			}
		}

		$data = array(
			'Province_Arr'=>$Province_Arr,
			'City_Arr'=>$City_Arr,
			'County_Arr'=>$County_Arr
		);
	}else{
		$data = array();
	}
	return $data;
}





/*
	### 使用用户名,ip,时间戳组合成token1并返回
	参一：用户名或openid
	参二：前后台类型，默认false后台，true 为前台
	return: 返回生成的token1
*/
function SetToken1($user){
	$ip = @$_SERVER["REMOTE_ADDR"];
	$token1 = md5($user.$ip.microtime());
	S('Token/'.$user,$token1);
	return $token1;
}


/*
	### 验证token1
	参一：用户名或openid
	参二：要验证的token1
	参三：前后台类型，默认false后台，true 为前台
	return: 返回生成的token1
*/
function VerifyToken1($user,$token1){
	$token2 = S('Token/'.$user);
	//S('ttttt',$token2."\r".$token1);
	if($token2 == $token1){
		return true;	//验证成功返回新的token1
	}else{
		return false;
	}
}



/*
	### 接收POST,GET,REQUEST数据，并处理特殊字符
	参一：接收名
	参二：默认空为get方式，get|post|all (request)
	return：返回将特殊字符处理后的数据
	示例：
		$number = I('number','post');
*/
function I($name,$type=''){
	switch($type){
		case 'p':$val = @$_POST[$name];break;
		case 'g':$val = @$_GET[$name];break;
		default:$val = @$_REQUEST[$name];break;
	}
	return trim($val);
}







/*
	### 检测变量
	示例：
		_checkVal($name,$pwd,,,);
*/
function _checkVal(){
	global $tmp_arr;
	$args = func_get_args();
	$stat = true;
	foreach($args as $k => $v){
		if(!$v){
			$tmp_arr['stat'] = 'err1';
			exit(json_encode($tmp_arr));
		}
	}
}









// #############################################################################












/*
	### 向状态集合文件设置字段
	参一：array   配置变量
	参二：string  要设置的状态字段名
	参三：fun     回调函数
	示例：
		require_once('../Class/UpYun/vendor/autoload.php');
		$serviceConfig = new \Upyun\Config($config['upyun_bucketname'],$config['upyun_username'],$config['upyun_password']);
		$up = new \Upyun\Upyun($serviceConfig);
		StatusSet($up,'abc21',function($res){
			dump($res);
		});
*/
// function StatusSet($up,$field,$fun=''){
// 	$FullConfigPath = '/Status/StatusSet.html';
// 	if($up->has($FullConfigPath)){	//状态文件存在
// 		$res = $up->read($FullConfigPath);
// 		$res2 = CorsTrim($res);
// 		if($res2){
// 			$res3 = json_decode($res2);
// 			$res3->$field = time();
// 			$FullConfigStr = 'Gets('.json_encode($res3).')';
// 			$res4 = $up->write($FullConfigPath,$FullConfigStr);
// 			if($fun){
// 				$fun($res4);
// 			}
// 		}else{
// 			$FullConfigArr = array($field=>time());
// 			$FullConfigStr = 'Gets('.json_encode($FullConfigArr).')';
// 			$res4 = $up->write($FullConfigPath,$FullConfigStr);
// 			if($fun){
// 				$fun($res4);
// 			}
// 		}
// 	}else{							//状态文件不存在
// 		$FullConfigArr = array($field=>time());
// 		$FullConfigStr = 'Gets('.json_encode($FullConfigArr).')';
// 		$res4 = $up->write($FullConfigPath,$FullConfigStr);
// 		if($fun){
// 			$fun($res4);
// 		}
// 	}
// }




/*
	### 去除upyun缓存文件的函数名及括号
	参一：string 缓存的数据字串
	参二：string 正则规则字串，默认为去除Gets()
	return：成功返回处理后的字串，失败返回false
*/
// function CorsTrim($res,$preg='/^Gets\(.*\)$/'){
// 	if(preg_match($preg,$res)){
// 		$start = strpos($res,'(')+1;
// 		$end = strrpos($res,')');
// 		return substr($res,$start,$end-$start);
// 	}else{
// 		return false;
// 	}
// }



/*
	### 将多个字段内容合md5成验证字串
	参数：可为多个不固定
	示例：
		$c = SetFieldsVCode('a','b');
*/
function SetFieldsVCode(){
	$str = 'aX1jehfhsbBNl3EW[CSEY2a328#@a4K#^_';
	foreach(func_get_args() as $v){
		$str .= $v;
	}
	return md5($str);
}





/*
	### 缩放图片
	参一：图片资源名
	参二：设置等比缩放的最大高度，默认300px
	参三：设置等比缩放的最大宽度，默认300px
	返回：缩放成功会返回 jpg格式的文件名
	示例：
		$new_name = ScaleImg($_FILES['banner']["tmp_name"]);
*/
function ScaleImg($imgs,$nw=300,$nh=300){
	if(!is_array($imgs)){
		exit('err11');
	}
	$ext = pathinfo($imgs['name'],PATHINFO_EXTENSION);
	switch($ext){
		case 'jpg':case 'JPG':case 'jpeg':case 'JPEG':
			$oimg=imagecreatefromjpeg($imgs['tmp_name']);	//引入要绽放的图片
			break;
		case 'png':case 'PNG':
			$oimg=imagecreatefrompng($imgs['tmp_name']);	//引入要绽放的图片
			break;
		case 'gif':case 'GIF':
			$oimg=imagecreatefromgif($imgs['tmp_name']);	//引入要绽放的图片
			break;
	}

	$ow=imagesx($oimg);		//获取要缩放图片的高宽
	$oh=imagesy($oimg);

	$new_name = 'a_'.ceil($imgs['size'] / 1024).'k.jpg';
	if($nw==0 || $nh==0){
		imagejpeg($oimg,$new_name);		//保存图片
	}else{
		if($ow && ($ow <$oh)){			//按公式将预设的宽高进行缩小并得到缩小后的值
			$nw=($nh / $oh) * $ow;
		}else{
			$nh=($nw / $ow) * $oh;
		}
		$nimg=imagecreatetruecolor($nw,$nh);	//创建一个画布，高宽使用缩放后的值，
		imagecopyresampled($nimg,$oimg,0,0,0,0,$nw,$nh,$ow,$oh);	//用函数将图片缩放
		imagejpeg($nimg,$new_name);		//保存图片
		imagedestroy($nimg);			//关闭资源
	}
	imagedestroy($oimg);
	return $new_name;
}











/*
	### 检测文件是否合法(大小，后缀) 
		参一：文件对象(必选)
		参二：文件大小(可选，默认500Kb)
		参三：文件后缀(可选，默认jpg,png,gif)
		return: 
			e1	文件类型不正确（参三使用默认时会检测文件类型)
			e2	文件大小超限
			e3	文件后缀不合法
			true 	通过检测返回true
		示例：
			img_select.onchange=function(){
				var file = img_select.files[0];
				alert(CheckFile(file,50000,['txt','zip']));
			}
*/
function UploadFile_Check($file,$size=512000,$file_exts=''){
	if($file['size'] > $size){
		return false;		//文件大小超限
	}
	$file_types = ['image/gif','image/jpeg','image/png'];	//文件类型过滤
	$ext = pathinfo($file['name'],PATHINFO_EXTENSION);
	if(!$file_exts){	//如果没有后缀，则后缀默认为三种图片后缀
		$file_exts = ['gif','GIF','jpeg','JPEG','jpg','JPG','png','PNG'];	//文件后缀过滤
		if(!array_search($file['type'],$file_types)){
			return false;		//文件类型不合法
		}
		if(!array_search($ext,$file_exts)){
			return false;		//文件类型不合法
		}
	}else{
		if(strripos($file_exts,$ext) === false){
			return false;	//文件类型不合法
		}
	}
	return true;
}








/*
	### 判官指定文件是否存在
	参一：upyun服务名及用户密码配置数组
	参二：要删除的文件路径 
	注意：需要将upyun插件文件放置到require_once目录中
	示例：
		UpyunHasFile($config,$path);
*/
function UpyunHasFile($config,$path){
	require_once('../Class/UpYun/vendor/autoload.php');
	$serviceConfig = new \Upyun\Config($config['upyun_bucketname'],$config['upyun_username'],$config['upyun_password']);
	$up = new \Upyun\Upyun($serviceConfig);
	return $up->has($path);
}





/*
	### 删除upyun指定文件
	参一：upyun服务名及用户密码配置数组
	参二：要删除的文件路径 
	注意：需要将upyun插件文件放置到require_once目录中
	示例：
		UpyunDelFile($config,$path);
*/
function UpyunDelFile($config,$path){
	require_once('../Class/UpYun/vendor/autoload.php');
	$serviceConfig = new \Upyun\Config($config['upyun_bucketname'],$config['upyun_username'],$config['upyun_password']);
	$up = new \Upyun\Upyun($serviceConfig);
	if(!is_array($path)){
		return $up->delete($path,true);
	}else{
		foreach($path as $v){
			$up->delete($v,true);
		}		
	}
	return true;
}



//删除upyun空目录
function UpyunDelDir($config,$path){
	require_once('../Class/UpYun/vendor/autoload.php');
	$serviceConfig = new \Upyun\Config($config['upyun_bucketname'],$config['upyun_username'],$config['upyun_password']);
	$up = new \Upyun\Upyun($serviceConfig);
	return $up->deleteDir($path);
}



/*
	### 向upyun写入文件
	参一：upyun服务名及用户密码配置数组
	参二：upyun上的保存的文件路径 
	参三：要写入的内容 
	参四：默认false为存储到数据服务，有值为存储到图片服务
	注意：需要将upyun插件文件放置到require_once目录中
	示例：
		UpyunAddFile($config,$path,'123');
*/
function UpyunAddFile($config,$path,$content){
	require_once('../Class/UpYun/vendor/autoload.php');
	$serviceConfig = new \Upyun\Config($config['upyun_bucketname'],$config['upyun_username'],$config['upyun_password']);
	$up = new \Upyun\Upyun($serviceConfig);
	return $up->write($path,$content);
}


/*
	### 缓存数据及版本号到upyun,并显示数据
	参一：$config 	array  	带有upyun配置的数组
	参二：$arr 		array  	要显示及缓存的数组
	参三：$uri 		string 	upyun缓存的路径  以 / 开始,不带文件后缀名
	参四：$tag_name string  版本号所在数据的下标或索引,默认空为不缓存tag1
	参五：$exit 	bool 	是否阻断向upyun缓存，默认false为不阻断，用于调试数据
	参六：$echo 	bool 	是否打印数据
	return 无
	示例：
		SaveUpyunAndtag1AndViewData($config,$arr3,$order_uri,'11');
*/
function SaveUpyunAndtag1AndViewData($config,$arr,$uri,$tag_name='',$exit=false,$echo=true){
	if(!$arr){
		$content = ' ';
	}else{
		$content = json_encode($arr);
	}
	if($echo){
		echo $content;
	}
	if($exit){
		exit;
	}
	$cahce_url = $uri.'.html';
	$r = UpyunAddFile($config,$cahce_url,$content);	//缓存数据到upyun
	if($tag_name){								//缓存版本号到upyun
		$tag1_url = $uri.'_tag1.html';
		UpyunAddFile($config,$tag1_url,''.$arr[$tag_name]);	//缓存数据到upyun
	}
}








/*
	### 上传图片到upyun ,检测 ，缩放组合函数 
	参一：array     upyun 配置数组
	参二：string    upyun 保存路径 (以/开始)
	参三：array 	接收的文件信息数组，如：$_FILES['banner']
	参四：int       限制上传文件的大小，可选，默认允许上传500k
	return          返回上传到upyun后的信息数组
	注：只能上传jpg,png,gif图片
	示例：
		$imgs = $_FILES['banner'];
		$full_path = '/StoreBanner/'.$openid.'_banner.jpg';
		$res_upyun = UploadImgToUpyun($config,$full_path,$imgs,1024*200);
		if(is_array($res_upyun)){
			$banner = $full_path;
		}else{
			exit('err5'); //文件上传失败
		}
*/
function UploadImgToUpyun($config,$full_path,$imgs,$size=''){
	//检测图片类型与大小,默认小于300k
	$size = $size?$size:300*1024;
	if(!UploadFile_Check($imgs,$size)){
		return 'err_img';  //文件类型或大小不合法
	}
	//文件缩放
	if($imgs['size'] > 1024 * 10){
		$new_name = ScaleImg($imgs,250,250); 	//缩放图片
	}else{
		$new_name = $imgs['tmp_name'];
	}
	$res_upyun = UpyunAddFile($config,$full_path,file_get_contents($new_name),1);
	unlink($new_name);
	return $res_upyun;
}














/*
	### 获取微信用户信息(openid及昵称头像等)
	参一：
		false：获取全信息 默认
		true： 只获取openid
	返回：
		获取成功返回信息
			当参一为false返回用户的全信息
			当参一为true时只返回用户的openid
		获取失败返回err
	示例：
		$user_info = GetOpenid();
*/
function GetOpenid($type=false){
	if(stripos($_SERVER['HTTP_USER_AGENT'],'micromessenger')){	//微信浏览器
		$time = time();
		$token = $time.'_'.substr(md5($time-1),5,16);
		//$back_uri = urlencode('http://store.shop.top/index.php'); //设置要使用该功能的站点域名
		$back_uri = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
		if($_GET['get_openid_res']){
			$res = @$_GET['get_openid_res'];
			if($type){
				if(preg_match('/^{.*}$/',$res)){
					$res_arr = json_decode($res,1);
					if($res_arr['openid']){
						$openid = md5($res_arr['openid']);
						return $openid;
					}
				}else{
					return "err";	//获取openid失败
				}
			}else{
				return $res;
			}
		}else{
			header('location:http://tools.bm123.top/wx_login/wx.php?get_openid_back_uri='.$back_uri.'&token='.$token);
		}
	}else{	//非微信浏览器
		echo "<script>alert('请使用微信浏览器!');</script>";
	}
}











/*
	### 对ip地址进行加密
	参一：ip地址
	返回：返回加密成功的数值，失败返回false
	示例：
		$a = IpEncrypt('127.10.10.1');	//加密
		echo IpDecrypt($a);	//解密
*/
function IpEncrypt($ip){
	if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
		return (((((ip2long($ip)-1024) * 2) - 2048 ) * 3 ) - 4096) * 4;
	}else{
		return false;
	}
}

/*
	### 对ip地址进行解密
	参一：ip地址
	返回：返回加密成功的数值，失败返回false
	示例：
		$a = IpEncrypt('127.10.10.1');	//加密
		echo IpDecrypt($a);	//解密
*/
function IpDecrypt($ip){
	return long2ip((((($ip/4)+4096)/3)+2048)/2 + 1024);
}
















/*
	### 反射，获取对象中的属性和方法(包含私有)
	参一：要获取的目标对象
		会直接打印出指定对象包含的属性和方法
	示例：
		$pdo = new PDO("mysql:host=192.168.1.12;dbname=t","tpcwre","123");
		Reflections($pdo);
*/
function Reflections($r){
	$f = new ReflectionObject($r);
	$a1 = $f->getProperties();
	d($a1);
	$a2 = $f->getMethods();
	d($a2);
}







/*
	### 验证远程token  
	参一：远程token值
	参二：过期时长，默认5秒
	return 	验证成功返回true,失败返回false
	示例：
		if(!CheckRemoteToken($_REQUEST['remote_token'])){
			exit('10002');	//远程token 验证失败
		}
*/
function CheckRemoteToken($t,$expire = 5){
	$limit = substr($t,(strlen($t)-12),2);
	$before = substr($t,0,(strlen($t)-12));
	$after = substr($t,(strlen($t)-10));
	$res1 = $after/2;
	if($res1 == $before/$limit && $res1 >= (time()-$expire)){		//5秒过期
		return true;
	}else{
		return false;
	}
}





/*
	### 生成远程token
	return 返回生成的远程token值
	示例：
		$remote_token = GenerateRemoteToken();
		$url = 'http://share.shop.xyz/interface.php?type=GetAreaInfo&remote_token='.$remote_token;


		  //JS 方式生成远程token
		  GenerateRemoteToken() {
		    var r1 = Math.floor(new Date().getTime()/1000);
		    var r2 = 10 + Math.ceil(Math.random()*9);
		    var r3 = r1 * r2;
		    var r4 = r1 * 2;
		    var r5 = ''+r3+r2+r4;
		    return r5;
		  }
*/
function GenerateRemoteToken(){
	$r1 = time();
	$r2 = rand(11,19);
	$r3 = $r1 * $r2;
	$r4 = $r1 * 2;
	$r5 = $r3.$r2.$r4;
	return $r5;
}






/*
	### GET方式Curl获取远程资源
	参一：$ourl (string)   请求地址
	return  (string) 	返回的结果
	示例：
		$res2 = CurlForGet($ourl);
*/
function CurlForGet($ourl){
	$curlobj = curl_init($ourl);
	curl_setopt($curlobj,CURLOPT_RETURNTRANSFER,true);
	curl_setopt($curlobj,CURLOPT_SSL_VERIFYPEER, 0);
	$output = curl_exec($curlobj);	
	curl_close($curlobj);
	return $output;
}



	



/*
	### 获取小程序的用户openid,session_key
	参一：code  小程序  wx.login 获取的code
	参二：appid	小程序的appid	(可选)
	参三：secret 小程序的secret (可选)
*/
function GetXcxOpenid($code,$appid=false,$secret=false){
	if(!$code){
		return false;
	}
	date_default_timezone_set('Asia/Chongqing');
	$appid = $appid?:'wx59b656c24cc6c189';
	$secret = $secret?:'36351f86780dc2d8555bed73b5173646';
	$ourl = "https://api.weixin.qq.com/sns/jscode2session?appid=".$appid."&secret=".$secret."&js_code=".$code."&grant_type=authorization_code";
	$curlobj = curl_init();
	curl_setopt($curlobj,CURLOPT_URL,$ourl);
	curl_setopt($curlobj,CURLOPT_RETURNTRANSFER,true);
	curl_setopt($curlobj,CURLOPT_SSL_VERIFYPEER, 0);
	$res = curl_exec($curlobj);	
	curl_close($curlobj);
	if(preg_match('/^{"session_key":.*$/',$res)){
		return json_decode($res,1)['openid'];
	}else{
		return false;
	}
}	

	


/*
	### 验证字段值是否合法
	参一：正则匹配模式
	参二：要验证的变量
	参三：非法后的提示内容或回调函数名
	示例：
		Field_Check(/.{3,}/,StoreMain_Name,'商户名太短!');
		或：
		Field_Check(/.{3,}/,StoreMain_Name,function(){
			Void_Token('商户名太短');
		});

	注：匹配中文时需使用 /php/u  u 表示使用unicode(utf-8)匹配方式 
		Field_Check('/^.{3,20}$|^[\x{4e00}-\x{9fa5}]{3,20}$/u',$name,'商户名长度为3-20个字符!');
*/
function Field_Check($p,$val){
	if(!preg_match($p,$val)){
		return false;
	}
	return true;
}



















//打印信息
function dump($data,$stat=false){
	echo '<pre>';
		var_dump($data);
	echo '</pre>';
	if($stat){
		exit;
	}
}




/*
	### 合并数据及参数并转换成json并缓存
		参一：要转成json的源数据
		参二：缓存文件的存放位置,空为不缓存
		参三：需要合并参数的关联数组
		参四：是直显还是return json数据，默认false为直显数据
		示例：
			Merge_Or_Make_Cache($res,'',array());
			或
			$res2 = Merge_Or_Make_Cache($res,'Cache/aa',array('a'=>'aaaa'),1,1);
			echo $res2;
*/
function Merge_Or_Make_Cache($data,$cache_path='',$arr=array(),$is_return=false){

	if(is_array($arr) && count($arr) > 0){
		foreach($arr as $k=>$v){
			$info[$k] = $v;
		}
	}
	$info['data'] = $data;
	if(!isset($info['time'])){
		$info['time'] = time() * 1000;
	}
	$cache = json_encode($info);
	if($cache_path != ''){
		$dir = dirname($cache_path);
		if(!is_dir($dir)){
			Mkdirs($dir);
		}
		file_put_contents($cache_path, $cache);
	}
	if($is_return){
		return $cache;
	}else{
		echo $cache;
	}
}



















/*
	###  获取指定日期的年月日当天零时的时间戳
		参一：$tag 获取哪天的的标记 如：要获取昨天的'-1 day'

		示例：
			echo $a = GetDateYmd('-1 day');		//1525968000
			echo date('Y-m-d H:i:s',$a);		//2018-05-11 00:00:00

*/
function GetDateYmd($tag){
	return strtotime(date('Y-m-d',strtotime($tag,time())));
}














/*
  	### 微信公众号向特定关注用户发送模板信息成品版
  	参一：first项（标题）
  	参二：keyword项数组(keyword1,keyword2...)
  	参三：remark项（结尾,可选，默认空）
	参四：跳转网址（可选，默认无）
	参五：发送到指定微信的openid（可选，默认free loop2的oid）
  	示例：
  		Wx_Template_Notice('待审核通知!',array('商户新增商品111',date('Y-m-d H:i:s')));

  		Wx_Template_Notice('待审核通知!',array('商户新增商品111',date('Y-m-d H:i:s')),'点击查看!','http://www.baidu.com','omTFa04k8h7CQlYUExqxX8q-gfR8');
*/
function Wx_Template_Notice($first,$keys,$remark='',$url="",$oid=''){
	$data = array(
		'first'=>array('value'=>$first,'color'=>'#ff0000'),
		'remark'=>array('value'=>$remark,'color'=>'#173177')
	);
	foreach($keys as $k=>$v){
		$tmp = array('keyword'.($k+1) =>array('value'=>$v,'color'=>'#0000ff'));
		$data = array_merge($data,$tmp);
	}
	$formwork =array(
		'touser'=>'omTFa02CiCTgB5FqQ4cHDcI7txXA',//free loop2
		'template_id'=>'Zn876eGea44kerfyxRAoY83Ve2ub3bt7T_SULmPexE8',	//服务通知
		'data'=>$data
	);
	if($url){
		$url_arr = array('url'=>$url);
		$formwork = array_merge($formwork,$url_arr);
	}
	if($oid){
		$oid_arr = array('touser'=>$oid);
		$formwork = array_replace($formwork, $oid_arr);
	}
	//dump($formwork,1);
	$res = Wx_Sent_Template_Msg($formwork);
	//var_dump($res);
}


/*
	### 微信公众号向特定关注用户发送模板信息
	参一：发送信息的数组
	return：返回操作状态字串 如：{"errcode":0,"errmsg":"ok","msgid":383394536703213568}
	注：
		1：需要在公众号 “基本配置 =》 ip白名单”  中设置请求access_token的ip白名单
		2：在公众号 “功能 =》 模板消息” 中选定并添加模板后，在"我的模板"中才会看到模板id。
	示例：
		//挪车模板
		$formwork =array(
			//'touser'=>'omTFa04k8h7CQlYUExqxX8q-gfR8',//用户openid free loop
			'touser'=>'omTFa02CiCTgB5FqQ4cHDcI7txX1A',//free loop2
			//'touser'=>'omTFa0-BG8RpFFRgZYTojLGCEWVk',
			//'touser'=>'omTFa01Wm3muXDPrCYDT-uVkwqAc',
			'template_id'=>'JRkXQcpMYreNuxQ3wTFOXCniQ9htDeDoo1e1Kw0r9oQ',	//挪车模板id
			'data'=>array(	//推送模板中对应的数据
				'first'=>array('value'=>'尊敬的用户您好，您有一条挪车请求。请尽快处理!','color'=>'#ff0000'),
				'keyword1'=>array('value'=>'挪车通知','color'=>'#00ff00'),
				'keyword2'=>array('value'=>'吉EEJ355','color'=>'#0000ff'),
				'keyword3'=>array('value'=>date('Y-m-d H:i:s'),'color'=>'#0000ff'),
				'remark'=>array('value'=>'感谢您使用前行微信挪车服务！祝您生活愉快！','color'=>'#173177')
			)
		);
		$res = sent_template_msg($formwork);
		var_dump($res);
*/
function Wx_Sent_Template_Msg($formwork){
	$access_token = file_get_contents('http://tools.bm123.top/wx/get_access_token.php?v=123');
	$formwork = json_encode($formwork);
	//发送请求
	$url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={$access_token}";
	$ch = curl_init();
	curl_setopt($ch, CURLOPT_URL,$url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
	curl_setopt($ch, CURLOPT_POST,1);
	curl_setopt($ch, CURLOPT_POSTFIELDS,$formwork);
	$data = curl_exec($ch);
	curl_close($ch);
	return $data;
}








/*
	### 检测并替换字串中的特殊字符为实体字符 (' , " , > , < , / , \)
	### 参一：源字串 
	### 参二：是否反解析，默认false为特殊字符转实体
	### 参三：不参与替换的字符,默认为空
	### return : 返回替换后的字串
	### 示例：
		$b = ChangeChar($a);	//转实体
		$val2 = ChangeChar($val,1); //实体转字符
*/
function ChangeChar($val,$stat=false,$sign=''){
	if($stat){
		$p = '/&#60/';
		$val = preg_replace($p,"<",$val);
		$p = '/&#62/';
		$val = preg_replace($p,">",$val);
		$p = '/&#39/';
		$val = preg_replace($p,"'",$val);
		$p = '/&#34/';
		$val = preg_replace($p,'"',$val);
		if($sign != '/'){
			$p = '/&#47/';
			$val = preg_replace($p,"/",$val);
		}
		$p = '/&#92/';
		$val = preg_replace($p,"\\",$val);
		$p = '/&#59/';
		$val = preg_replace($p,";",$val);

		$p = '/&#40/';
		$val = preg_replace($p,"(",$val);

		$p = '/&#41/';
		$val = preg_replace($p,")",$val);

		//$p = '/&nbsp/';
		//$val = preg_replace($p," ",$val);
		return $val;
	}else{
		$p ='/</';
		$val = preg_replace($p,"&#60",$val);
		$p ='/>/';
		$val = preg_replace($p,"&#62",$val);
		$p ="/'/";
		$val = preg_replace($p,"&#39",$val);
		$p ='/"/';
		$val = preg_replace($p,"&#34",$val);
		if($sign != '/'){
			$p = '/\//';
			$val = preg_replace($p,"&#47",$val);
		}
		$p = '/\\\/';
		$val = preg_replace($p,"&#92",$val);
		$p = '/;/';
		$val = preg_replace($p,"&#59",$val);

		$p = '/\(/';
		$val = preg_replace($p,"&#40",$val);
		$p = '/\)/';
		$val = preg_replace($p,"&#41",$val);
		
		//$p = '/\s/';
		//$val = preg_replace($p,"&nbsp",$val);
		return $val;
	}
}





/*
	### 永久缓存数据
	参一：缓存路径 (string)
	参二：缓存的值（string）
	return：
		当只有参一时是获取缓存并返回空或对应的值
		当有两个参数时是设置缓存，无返回值
	示例：
		S('a','aaa');	//设置
		echo S('a');	//获取
*/
function S($p,$v=false){
	if($v === ''){
		if(is_file($p)){
			unlink($p);
		}
		return;
	}
	if($v !== false){
		if(!is_dir(dirname($p))){
			Mkdirs(dirname($p));
		}
		file_put_contents($p,$v);
	}else{
		if(!file_exists($p)){
			return;
		}
		return file_get_contents($p);
	}
}



/*
	### 向指定文件写入内容(自动创建不存在目录)
	参一：$psth (string) 	要写入文件的路径
	参二：$content (string) 	要写入的内容
	示例：
*/
//function WriteFile($path,$content){
function F($path,$content=false){
	if(func_num_args() > 1){	//存储数据
		$dir = dirname($path);
		if(!is_dir($dir)){
			Mkdirs($dir);
		}
		file_put_contents($path,$content);
	}else{ 						//获取数据
		if(file_exists($path)){
			return file_get_contents($path);
		}
	}
}





/*
	### 递归创建目录
	### 参一：目录路径
*/
function Mkdirs($p){
	if(!is_dir($p)){
		Mkdirs(dirname($p),0777,true);
		mkdir($p);
	}
}




//递归删除目录及文件
function DelDirs($p){
	if(is_file($p)){
		unlink($p);
	}
	if(is_dir($p)){
		$op = opendir($p);
		while($rd = readdir($op)){
			if($rd == '.' || $rd == '..'){
				continue;
			}
			$p2 = $p.'/'.$rd;
			DelDirs($p2);
		}
		rmdir($p);
		closedir($op);
	}
}











/*
	### 判断表数据总条数是否超过阀值，并返回起始值
	参一：pdo对象
	参二：表名
	参三：主键字段名
	参四：设置超越多少就获取倒值的阀值
	参五：设置倒数的条数,默认100万，默认50万,且该 值不能超过参四
	返回：主键数值
	示例：
		echo CheckMaxPriOrGetStartPri($pdo,'shop_store','store_id',5,3);
*/
function CheckMaxPriOrGetStartPri($pdo,$table,$pri,$limit_val=1000000,$desc=false){
	if(!@$_SESSION['pri_id']){
		$limit_val = intval($limit_val);
		if(!$desc || intval($desc) > $limit_val){
			$desc = ceil($limit_val/2);
		}else{
			$desc = intval($desc);
		}
		$sql_count = "select count(*) as c from {$table}";
		$res_count = $pdo->dql($sql_count,array(),1);
		if(intval($res_count['c']) > intval($limit_val)){	//当总条数大于阀值时，则获取倒数指定条数的id值
			$sql_get_start = "select {$pri} from {$table} where {intval($pri)} > (select {$pri} from {$table} order by {$pri} desc limit {$desc},1) limit 1";
			$res_get_start = $pdo->dql($sql_get_start,array(),1);
			$_SESSION['pri_id'] = $res_get_start[$pri];
		}else{
			$_SESSION['pri_id'] = 0;
		}
	}
	return $_SESSION['pri_id'];
}	









/*
	### 获取指定表中倒数多少条的id值，如果条数不足则反回1
	参一：$pdo    object     pdo对象
	参二：$table  string     表名
	参三：$limit  number     是倒数的条数
	参四：$id     string     主键字段名，默认为 ‘id’
	说明：查询表中指定倒数条数的主键值，查询不到时返回 1
	示例：
		echo GetDescId($pdo,'shop_goods',3);
*/
function GetDescId($pdo,$table,$limit=50000,$id='id'){
	$sql = "select count(*) c from {$table}";
	$res = $pdo->dql($sql,array(),1);
	if($res && $res['c'] > $limit){
		$sql2 = "select {$id} from {$table} order by {$id} desc limit {$limit},1";
		$res2 = $pdo->dql($sql2,array(),1);
		if($res2){
			return $res2[$id];
		}else{
			return 1;
		}
	}else{
		return 1;
	}
}


